﻿Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.ComponentModel.Design.Serialization
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Security.Permissions
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler
Imports System.Workflow.ComponentModel.Serialization
Imports System.Xml

Namespace System.Workflow.ComponentModel.Design
    <PermissionSet(SecurityAction.LinkDemand, Name:="FullTrust"), PermissionSet(SecurityAction.InheritanceDemand, Name:="FullTrust")> _
    Public MustInherit Class WorkflowDesignerLoader
        Inherits BasicDesignerLoader
        ' Methods
        Shared Sub New()
            ComponentDispenser.RegisterComponentExtenders(GetType(CustomActivityDesignerAdapter), New IExtenderProvider() { New CustomActivityPropertyExtender })
        End Sub

        Protected Sub New()
        End Sub

        Public Sub AddActivityToDesigner(ByVal activity As Activity)
            If (activity Is Nothing) Then
                Throw New ArgumentNullException("activity")
            End If
            Dim service As IDesignerHost = [TryCast](MyBase.GetService(GetType(IDesignerHost)),IDesignerHost)
            If (service Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(IDesignerHost).FullName }))
            End If
            If ((activity.Parent Is Nothing) AndAlso (service.RootComponent Is Nothing)) Then
                Dim str As String = [TryCast](activity.GetValue(WorkflowMarkupSerializer.XClassProperty),String)
                Dim name As String = If(Not String.IsNullOrEmpty(str), Helpers.GetClassName(str), Helpers.GetClassName(activity.GetType.FullName))
                service.Container.Add(activity, name)
            Else
                service.Container.Add(activity, activity.QualifiedName)
            End If
            If TypeOf activity Is CompositeActivity Then
                Dim activity2 As Activity
                For Each activity2 In Helpers.GetNestedActivities([TryCast](activity,CompositeActivity))
                    service.Container.Add(activity2, activity2.QualifiedName)
                Next
            End If
        End Sub

        Friend Shared Sub AddActivityToDesigner(ByVal serviceProvider As IServiceProvider, ByVal activity As Activity)
            Dim service As WorkflowDesignerLoader = [TryCast](serviceProvider.GetService(GetType(WorkflowDesignerLoader)),WorkflowDesignerLoader)
            If (service Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(WorkflowDesignerLoader).FullName }))
            End If
            service.AddActivityToDesigner(activity)
        End Sub

        Public Overrides Sub Dispose()
            If (Not Me.eventsCoordinator Is Nothing) Then
                DirectCast(Me.eventsCoordinator, IDisposable).Dispose
                Me.eventsCoordinator = Nothing
            End If
            If (Not Me.customActivityDesignerAdapter Is Nothing) Then
                DirectCast(Me.customActivityDesignerAdapter, IDisposable).Dispose
                Me.customActivityDesignerAdapter = Nothing
            End If
            Dim service As IExtenderProviderService = [TryCast](MyBase.GetService(GetType(IExtenderProviderService)),IExtenderProviderService)
            If (Not service Is Nothing) Then
                Dim provider As IExtenderProvider
                For Each provider In ComponentDispenser.Extenders
                    service.RemoveExtenderProvider(provider)
                Next
            End If
            If (Not MyBase.LoaderHost Is Nothing) Then
                If (Not Me.createdServices Is Nothing) Then
                    Dim type As Type
                    For Each type In Me.createdServices.Keys
                        MyBase.LoaderHost.RemoveService(type)
                    Next
                    Me.createdServices.Clear
                    Me.createdServices = Nothing
                End If
                MyBase.LoaderHost.RemoveService(GetType(WorkflowDesignerLoader))
            End If
            MyBase.Dispose
        End Sub

        Public Overrides Sub Flush()
            MyBase.Flush
        End Sub

        Public Overridable Sub ForceReload()
            MyBase.Reload(ReloadOptions.Force)
        End Sub

        Public MustOverride Function GetFileReader(ByVal filePath As String) As TextReader

        Public MustOverride Function GetFileWriter(ByVal filePath As String) As TextWriter

        Protected Overrides Sub Initialize()
            MyBase.Initialize
            Dim type As Type = Type.GetType("System.Workflow.Activities.InvokeWorkflowActivity, System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
            If (Not type Is Nothing) Then
                TypeDescriptor.AddAttributes(type, New Attribute() { New DesignerAttribute(GetType(InvokeWorkflowDesigner), GetType(IDesigner)) })
            End If
            MyBase.LoaderHost.AddService(GetType(WorkflowDesignerLoader), Me)
            Dim callback As ServiceCreatorCallback = New ServiceCreatorCallback(AddressOf Me.OnCreateService)
            If (MyBase.LoaderHost.GetService(GetType(IWorkflowCompilerOptionsService)) Is Nothing) Then
                MyBase.LoaderHost.AddService(GetType(IWorkflowCompilerOptionsService), callback)
            End If
            If (MyBase.LoaderHost.GetService(GetType(IIdentifierCreationService)) Is Nothing) Then
                MyBase.LoaderHost.AddService(GetType(IIdentifierCreationService), callback)
            End If
            If (MyBase.LoaderHost.GetService(GetType(ComponentSerializationService)) Is Nothing) Then
                MyBase.LoaderHost.AddService(GetType(ComponentSerializationService), callback)
            End If
            MyBase.LoaderHost.RemoveService(GetType(IReferenceService))
            If (MyBase.LoaderHost.GetService(GetType(IReferenceService)) Is Nothing) Then
                MyBase.LoaderHost.AddService(GetType(IReferenceService), callback)
            End If
            If (MyBase.LoaderHost.GetService(GetType(IDesignerVerbProviderService)) Is Nothing) Then
                MyBase.LoaderHost.AddService(GetType(IDesignerVerbProviderService), callback)
            End If
            Dim service As IExtenderProviderService = [TryCast](MyBase.GetService(GetType(IExtenderProviderService)),IExtenderProviderService)
            If (Not service Is Nothing) Then
                Dim provider As IExtenderProvider
                For Each provider In ComponentDispenser.Extenders
                    service.AddExtenderProvider(provider)
                Next
            End If
            Me.customActivityDesignerAdapter = New CustomActivityDesignerAdapter(MyBase.LoaderHost)
        End Sub

        Private Sub LoadDesignerLayout(<Out> ByRef layoutErrors As IList)
            layoutErrors = Nothing
            Dim designerLayoutFileName As String = Me.DesignerLayoutFileName
            Dim safeRootDesigner As IWorkflowRootDesigner = ActivityDesigner.GetSafeRootDesigner(MyBase.LoaderHost)
            If (((Not safeRootDesigner Is Nothing) AndAlso safeRootDesigner.SupportsLayoutPersistence) AndAlso File.Exists(designerLayoutFileName)) Then
                [Using] reader As TextReader = Me.GetFileReader(designerLayoutFileName)
                    If (Not reader Is Nothing) Then
                        [Using] reader2 As XmlReader = XmlReader.Create(reader)
                            Me.LoadDesignerLayout(reader2, layoutErrors)
                        End [Using]
                    End If
                End [Using]
            End If
        End Sub

        Protected Sub LoadDesignerLayout(ByVal layoutReader As XmlReader, <Out> ByRef layoutLoadErrors As IList)
            If (layoutReader Is Nothing) Then
                Throw New ArgumentNullException("layoutReader")
            End If
            Dim list As New ArrayList
            layoutLoadErrors = list
            Dim designer As ActivityDesigner = Nothing
            Dim service As IDesignerHost = [TryCast](MyBase.GetService(GetType(IDesignerHost)),IDesignerHost)
            If ((Not service Is Nothing) AndAlso (Not service.RootComponent Is Nothing)) Then
                designer = [TryCast](service.GetDesigner(service.RootComponent),ActivityDesigner)
            End If
            If (Not designer Is Nothing) Then
                If designer.SupportsLayoutPersistence Then
                    Dim manager As New DesignerSerializationManager(MyBase.LoaderHost)
                    [Using] manager.CreateSession
                        Dim serializationManager As New WorkflowMarkupSerializationManager(manager)
                        serializationManager.AddSerializationProvider(New ActivityDesignerLayoutSerializerProvider)
                        Try 
                            New WorkflowMarkupSerializer().Deserialize(serializationManager, layoutReader)
                        Catch exception As Exception
                            list.Add(New WorkflowMarkupSerializationException(SR.GetString("Error_LayoutDeserialization"), exception))
                        Finally
                            If (Not manager.Errors Is Nothing) Then
                                list.AddRange(manager.Errors)
                            End If
                        End Try
                        Return
                    End [Using]
                End If
                list.Add(New WorkflowMarkupSerializationException(SR.GetString("Error_LayoutSerializationPersistenceSupport")))
            Else
                list.Add(New WorkflowMarkupSerializationException(SR.GetString("Error_LayoutSerializationRootDesignerNotFound")))
            End If
        End Sub

        Private Sub LoadDesignerLayoutFromResource(<Out> ByRef layoutErrors As IList)
            layoutErrors = Nothing
            Dim safeRootDesigner As IWorkflowRootDesigner = ActivityDesigner.GetSafeRootDesigner(MyBase.LoaderHost)
            If ((Not safeRootDesigner Is Nothing) AndAlso safeRootDesigner.SupportsLayoutPersistence) Then
                Dim type As Type = safeRootDesigner.Component.GetType
                Dim manifestResourceName As String = (type.Name & ".layout")
                Me.LoadDesignerLayoutFromResource(type, manifestResourceName, layoutErrors)
            End If
        End Sub

        Protected Sub LoadDesignerLayoutFromResource(ByVal type As Type, ByVal manifestResourceName As String, <Out> ByRef errors As IList)
            If (type Is Nothing) Then
                Throw New ArgumentNullException("type")
            End If
            If (manifestResourceName Is Nothing) Then
                Throw New ArgumentNullException("manifestResourceName")
            End If
            If (manifestResourceName.Length = 0) Then
                Throw New ArgumentException(SR.GetString("Error_ParameterCannotBeEmpty"), "manifestResourceName")
            End If
            errors = New ArrayList
            Dim manifestResourceStream As Stream = type.Module.Assembly.GetManifestResourceStream(type, manifestResourceName)
            If (manifestResourceStream Is Nothing) Then
                manifestResourceStream = type.Module.Assembly.GetManifestResourceStream(manifestResourceName)
            End If
            If (Not manifestResourceStream Is Nothing) Then
                [Using] reader As XmlReader = XmlReader.Create(manifestResourceStream)
                    If (Not reader Is Nothing) Then
                        Me.LoadDesignerLayout(reader, errors)
                    End If
                End [Using]
            End If
        End Sub

        Private Function OnCreateService(ByVal container As IServiceContainer, ByVal serviceType As Type) As Object
            Dim obj2 As Object = Nothing
            If (serviceType Is GetType(ComponentSerializationService)) Then
                obj2 = New XomlComponentSerializationService(MyBase.LoaderHost)
            ElseIf (serviceType Is GetType(IReferenceService)) Then
                obj2 = New ReferenceService(MyBase.LoaderHost)
            ElseIf (serviceType Is GetType(IIdentifierCreationService)) Then
                obj2 = New IdentifierCreationService(container, Me)
            ElseIf (serviceType Is GetType(IWorkflowCompilerOptionsService)) Then
                obj2 = New WorkflowCompilerOptionsService
            ElseIf (serviceType Is GetType(IDesignerVerbProviderService)) Then
                obj2 = New DesignerVerbProviderService
            End If
            If (Not obj2 Is Nothing) Then
                If (Me.createdServices Is Nothing) Then
                    Me.createdServices = New Hashtable
                End If
                Me.createdServices.Item(serviceType) = obj2
            End If
            Return obj2
        End Function

        Protected Overrides Sub OnEndLoad(ByVal successful As Boolean, ByVal errors As ICollection)
            MyBase.OnEndLoad(successful, errors)
            If successful Then
                Dim rootDesigner As ActivityDesigner = ActivityDesigner.GetRootDesigner(MyBase.LoaderHost)
                If ((Me.eventsCoordinator Is Nothing) AndAlso ((rootDesigner Is Nothing) OrElse (rootDesigner.ParentDesigner Is Nothing))) Then
                    Me.eventsCoordinator = New WorkflowDesignerEventsCoordinator(MyBase.LoaderHost)
                End If
                Try 
                    Me.loadingDesignerLayout = True
                    Dim designerLayoutFileName As String = Me.DesignerLayoutFileName
                    Dim layoutErrors As IList = Nothing
                    If File.Exists(designerLayoutFileName) Then
                        Me.LoadDesignerLayout(layoutErrors)
                    ElseIf (Me.InDebugMode OrElse ((Not ActivityDesigner.GetRootDesigner(MyBase.LoaderHost) Is Nothing) AndAlso (Not ActivityDesigner.GetRootDesigner(MyBase.LoaderHost).ParentDesigner Is Nothing))) Then
                        Me.LoadDesignerLayoutFromResource(layoutErrors)
                    End If
                    If (Not layoutErrors Is Nothing) Then
                        If (errors Is Nothing) Then
                            errors = New ArrayList
                        End If
                        Dim list2 As IList = [TryCast](errors,IList)
                        If (Not list2 Is Nothing) Then
                            Dim obj2 As Object
                            For Each obj2 In layoutErrors
                                list2.Add(obj2)
                            Next
                        End If
                    End If
                Finally
                    Me.loadingDesignerLayout = False
                End Try
            End If
        End Sub

        Protected Overrides Sub PerformFlush(ByVal serializationManager As IDesignerSerializationManager)
            Me.SaveDesignerLayout
        End Sub

        Protected Overrides Sub PerformLoad(ByVal serializationManager As IDesignerSerializationManager)
        End Sub

        Public Sub RemoveActivityFromDesigner(ByVal activity As Activity)
            If (activity Is Nothing) Then
                Throw New ArgumentNullException("activity")
            End If
            Dim service As IDesignerHost = [TryCast](MyBase.GetService(GetType(IDesignerHost)),IDesignerHost)
            If (service Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(IDesignerHost).FullName }))
            End If
            service.DestroyComponent(activity)
            If TypeOf activity Is CompositeActivity Then
                Dim activity2 As Activity
                For Each activity2 In Helpers.GetNestedActivities([TryCast](activity,CompositeActivity))
                    service.DestroyComponent(activity2)
                Next
            End If
        End Sub

        Friend Shared Sub RemoveActivityFromDesigner(ByVal serviceProvider As IServiceProvider, ByVal activity As Activity)
            Dim service As WorkflowDesignerLoader = [TryCast](serviceProvider.GetService(GetType(WorkflowDesignerLoader)),WorkflowDesignerLoader)
            If (service Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(WorkflowDesignerLoader).FullName }))
            End If
            service.RemoveActivityFromDesigner(activity)
        End Sub

        Private Sub SaveDesignerLayout()
            Dim designerLayoutFileName As String = Me.DesignerLayoutFileName
            Dim safeRootDesigner As ActivityDesigner = ActivityDesigner.GetSafeRootDesigner(MyBase.LoaderHost)
            If ((Not String.IsNullOrEmpty(designerLayoutFileName) AndAlso (Not safeRootDesigner Is Nothing)) AndAlso safeRootDesigner.SupportsLayoutPersistence) Then
                [Using] writer As TextWriter = Me.GetFileWriter(designerLayoutFileName)
                    If (Not writer Is Nothing) Then
                        Dim layoutSaveErrors As IList = Nothing
                        [Using] writer2 As XmlWriter = Helpers.CreateXmlWriter(writer)
                            Me.SaveDesignerLayout(writer2, safeRootDesigner, layoutSaveErrors)
                        End [Using]
                    End If
                End [Using]
            End If
        End Sub

        Protected Sub SaveDesignerLayout(ByVal layoutWriter As XmlWriter, ByVal rootDesigner As ActivityDesigner, <Out> ByRef layoutSaveErrors As IList)
            If (layoutWriter Is Nothing) Then
                Throw New ArgumentNullException("layoutWriter")
            End If
            If (rootDesigner Is Nothing) Then
                Throw New ArgumentNullException("rootDesigner")
            End If
            Dim list As New ArrayList
            layoutSaveErrors = list
            If rootDesigner.SupportsLayoutPersistence Then
                Dim manager As New DesignerSerializationManager(MyBase.LoaderHost)
                [Using] manager.CreateSession
                    Dim serializationManager As New WorkflowMarkupSerializationManager(manager)
                    serializationManager.AddSerializationProvider(New ActivityDesignerLayoutSerializerProvider)
                    Try 
                        New WorkflowMarkupSerializer().Serialize(serializationManager, layoutWriter, rootDesigner)
                    Catch exception As Exception
                        list.Add(New WorkflowMarkupSerializationException(SR.GetString("Error_LayoutSerialization"), exception))
                    Finally
                        If (Not manager.Errors Is Nothing) Then
                            list.AddRange(manager.Errors)
                        End If
                    End Try
                    Return
                End [Using]
            End If
            list.Add(New WorkflowMarkupSerializationException(SR.GetString("Error_LayoutSerializationPersistenceSupport")))
        End Sub

        Friend Sub SetModified(ByVal modified As Boolean)
            If (((Not MyBase.LoaderHost Is Nothing) AndAlso Not MyBase.LoaderHost.Loading) AndAlso Not Me.loadingDesignerLayout) Then
                Me.OnModifying
                MyBase.Modified = modified
            End If
        End Sub


        ' Properties
        Private ReadOnly Property DesignerLayoutFileName As String
            Get
                Dim fileName As String = Me.FileName
                If Not String.IsNullOrEmpty(fileName) Then
                    fileName = (Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName)) & ".layout")
                End If
                Return fileName
            End Get
        End Property

        Public MustOverride ReadOnly Property FileName As String

        Public Overridable ReadOnly Property InDebugMode As Boolean
            Get
                Return False
            End Get
        End Property


        ' Fields
        Private createdServices As Hashtable
        Private customActivityDesignerAdapter As CustomActivityDesignerAdapter
        Friend Const DesignerLayoutFileExtension As String = ".layout"
        Private eventsCoordinator As WorkflowDesignerEventsCoordinator
        Private loadingDesignerLayout As Boolean
    End Class
End Namespace

